package com.zhengxiang.onlinexamination.utils;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONObject;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import static org.apache.catalina.manager.host.Constants.CHARSET;

/**
 * <p>
 * </p>
 * 
 * @author:Crow
 * @Date: 2019年9月11日 上午10:12:39
 */
@Log4j2
public class QRCodeUtil {
	private static final int QRCOLOR = 0xFF000000; // 默认是黑色
	private static final int BGWHITE = 0xFFFFFFFF; // 背景颜色

	private static final int WIDTH = 400; // 二维码宽
	private static final int HEIGHT = 400; // 二维码高

	/**
	 * 小程序id
	 */
	public final static String API_KEY = "wxd8119cd63add122b";
	//测试
//	public final static String API_KEY = "wx807510a6581cb90d";

	/**
	 * 小程序密钥
	 */
	public final static String SECRET_KEY = "e731e4d3535379b5f079331f42c21ee3";
	//测试
//	public final static String SECRET_KEY = "c648d3463a0779672221c5ce4258b355";

	/**
	 * 用于获取access_token
	 *
	 * @return access_token
	 * @throws Exception
	 */
	public static String getWxToken() {

		String requestUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + API_KEY
				+ "&secret=" + SECRET_KEY;

		String body = HttpRequest.post(requestUrl).execute().body();

		JSONObject jsonObject = JSONObject.parseObject(body);
		String accesstoken = jsonObject.getString("access_token");
		return accesstoken;
	}

	/**
	 * 生成带参小程序二维码
	 *
	 * @param parameter    参数
	 * @param accessToken token
	 * @throws IOException
	 */
	public static InputStream getWxQr(String parameter, String accessToken, String page) {
		String requestUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken;
		// 发送请求参数
		JSONObject paramJson = new JSONObject();
		paramJson.put("scene", parameter);
		paramJson.put("page", page);
		paramJson.put("width", 430);
		paramJson.put("auto_color", true);
		paramJson.put("check_path", false);
		//开发版
//		paramJson.put("env_version","develop");
		//体验版
//		paramJson.put("env_version","trial");
		//正式版
		paramJson.put("env_version","release");
		HttpResponse execute = null;
		try {
			log.info("二维码请求参数[{}]", paramJson.toJSONString());
			execute = HttpRequest.post(requestUrl).body(paramJson.toJSONString()).execute();
			return execute.bodyStream();
		} catch (Exception e) {
			log.info("二维码请求失败，返回值[{}]", execute.body());
			return null;
		}
	}
	/**
	 * 生成简易二维码
	 * 
	 * @param text
	 * @param width
	 * @param height
	 * @return
	 * @throws WriterException
	 * @throws IOException
	 */
	public static BitMatrix generateQRCodeImage(String text, int width, int height,boolean deleteWhite)
			throws WriterException, IOException {
		QRCodeWriter qrCodeWriter = new QRCodeWriter();
		BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
		if(deleteWhite){
			bitMatrix = deleteWhite(bitMatrix);
		}
		return bitMatrix;
	}
	/**
	 *  删除生成的二维码周围的白边，根据审美决定是否删除
	 * @param matrix BitMatrix对象
	 * @return BitMatrix对象
	 * */
	private static BitMatrix deleteWhite(BitMatrix matrix) {
		int[] rec = matrix.getEnclosingRectangle();
		int resWidth = rec[2] + 1;
		int resHeight = rec[3] + 1;

		BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
		resMatrix.clear();
		for (int i = 0; i < resWidth; i++) {
			for (int j = 0; j < resHeight; j++) {
				if (matrix.get(i + rec[0], j + rec[1])) {
					resMatrix.set(i, j);
				}
			}
		}
		return resMatrix;
	}
	// 用于设置QR二维码参数
	private static Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>() {
		private static final long serialVersionUID = 1L;
		{
			put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);// 设置QR二维码的纠错级别（H为最高级别）具体级别信息
			put(EncodeHintType.CHARACTER_SET, "utf-8");// 设置编码方式
			put(EncodeHintType.MARGIN, 0);
		}
	};

	/**
	 * 生成带logo的二维码图片
	 * 
	 * @param logoFile logo路径
	 * @param codeFile 生成二维码保存文件
	 * @param qrUrl    二维码存储链接
	 * @param note     二维码下方显示文字
	 * @return
	 */
	public static BufferedImage drawLogoQRCode(File logoFile, File codeFile, String qrUrl, String note) {
		BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
		try {
			MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
			// 参数顺序分别为：编码内容，编码类型，生成图片宽度，生成图片高度，设置参数
			BitMatrix bm = multiFormatWriter.encode(qrUrl, BarcodeFormat.QR_CODE, WIDTH, HEIGHT, hints);

			// 开始利用二维码数据创建Bitmap图片，分别设为黑（0xFFFFFFFF）白（0xFF000000）两色
			for (int x = 0; x < WIDTH; x++) {
				for (int y = 0; y < HEIGHT; y++) {
					// 二维码颜色（RGB）
					int num1 = (int) (50 - (50.0 - 13.0) / HEIGHT * (y + 1));
					int num2 = (int) (165 - (165.0 - 72.0) / HEIGHT * (y + 1));
					int num3 = (int) (162 - (162.0 - 107.0) / HEIGHT * (y + 1));
					Color color = new Color(num1, num2, num3);
					int colorInt = color.getRGB();
					image.setRGB(x, y, bm.get(x, y) ? colorInt : BGWHITE);
				}
			}

			int width = image.getWidth();
			int height = image.getHeight();
			if (Objects.nonNull(logoFile) && logoFile.exists()) {
				// 构建绘图对象
				Graphics2D g = image.createGraphics();
				// 读取Logo图片
				BufferedImage logo = ImageIO.read(logoFile);
				// 开始绘制logo图片
				g.drawImage(logo, (width * 2 / 5) - 8, (height * 2 / 5) - 8, width * 2 / 8, height * 2 / 8, null);
				g.dispose();
				logo.flush();
			}

			// 自定义文本描述
			if (!StringUtils.isNotEmpty(note)) {
				// 新的图片，把带logo的二维码下面加上文字
				BufferedImage outImage = new BufferedImage(400, 445, BufferedImage.TYPE_4BYTE_ABGR);
				Graphics2D outg = outImage.createGraphics();
				// 画二维码到新的面板
				outg.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
				// 画文字到新的面板
				outg.setColor(Color.BLACK);
				outg.setFont(new Font("楷体", Font.BOLD, 30)); // 字体、字型、字号
				int strWidth = outg.getFontMetrics().stringWidth(note);
				if (strWidth > 399) {
					// //长度过长就截取前面部分
					// 长度过长就换行
					String note1 = note.substring(0, note.length() / 2);
					String note2 = note.substring(note.length() / 2, note.length());
					int strWidth1 = outg.getFontMetrics().stringWidth(note1);
					int strWidth2 = outg.getFontMetrics().stringWidth(note2);
					outg.drawString(note1, 200 - strWidth1 / 2, height + (outImage.getHeight() - height) / 2 + 12);
					BufferedImage outImage2 = new BufferedImage(400, 485, BufferedImage.TYPE_4BYTE_ABGR);
					Graphics2D outg2 = outImage2.createGraphics();
					outg2.drawImage(outImage, 0, 0, outImage.getWidth(), outImage.getHeight(), null);
					outg2.setColor(Color.BLACK);
					outg2.setFont(new Font("宋体", Font.BOLD, 30)); // 字体、字型、字号
					outg2.drawString(note2, 200 - strWidth2 / 2,
							outImage.getHeight() + (outImage2.getHeight() - outImage.getHeight()) / 2 + 5);
					outg2.dispose();
					outImage2.flush();
					outImage = outImage2;
				} else {
					outg.drawString(note, 200 - strWidth / 2, height + (outImage.getHeight() - height) / 2 + 12); // 画文字
				}
				outg.dispose();
				outImage.flush();
				image = outImage;
			}
			image.flush();
			if (codeFile != null) {
				ImageIO.write(image, "png", codeFile); // TODO
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return image;
	}

	/**
	 * 二维码添加文字
	 * @param image
	 * @param note
	 * @throws WriterException
	 */
	public static BufferedImage addBottomText(BufferedImage image,String note){
		BufferedImage outImage = new BufferedImage(430, 480, BufferedImage.TYPE_INT_BGR);
		int width = image.getWidth();
		int height = image.getHeight();
		if (!StringUtils.isNotEmpty(note)) {
			// 新的图片，把带logo的二维码下面加上文字
			Graphics2D outg = outImage.createGraphics();
			// 画二维码到新的面板
			outg.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
			// 画文字到新的面板
			outg.setColor(Color.white);
			outg.setFont(new Font("楷体", Font.BOLD, 30)); // 字体、字型、字号
			int strWidth = outg.getFontMetrics().stringWidth(note);
			if (strWidth > 399) {
				// //长度过长就截取前面部分
				// 长度过长就换行
				String note1 = note.substring(0, note.length() / 2);
				String note2 = note.substring(note.length() / 2, note.length());
				int strWidth1 = outg.getFontMetrics().stringWidth(note1);
				int strWidth2 = outg.getFontMetrics().stringWidth(note2);
				outg.drawString(note1, 200 - strWidth1 / 2, height + (outImage.getHeight() - height) / 2 + 12);
				BufferedImage outImage2 = new BufferedImage(400, 480, BufferedImage.TYPE_INT_BGR);
				Graphics2D outg2 = outImage2.createGraphics();
				outg2.drawImage(outImage, 0, 0, outImage.getWidth(), outImage.getHeight(), null);
				outg2.setColor(Color.BLACK);
				outg2.setFont(new Font("宋体", Font.BOLD, 30)); // 字体、字型、字号
				outg2.drawString(note2, 200 - strWidth2 / 2,
						outImage.getHeight() + (outImage2.getHeight() - outImage.getHeight()) / 2 + 5);
				outg2.dispose();
				outImage2.flush();
				outImage = outImage2;
			} else {
				outg.drawString(note, 200 - strWidth / 2, height + (outImage.getHeight() - height) / 2 + 12); // 画文字
			}
			outg.dispose();
		}
		return outImage;
	}
	/**
	 * 生成二维码
	 *
	 * @param content    内容
	 * @param width      二维码宽度
	 * @param height     二维码高度
	 * @param logoUrl    logo 在线地址
	 * @param logoWidth  logo 宽度
	 * @param logoHeight logo 高度
	 * @return
	 */
	public static BufferedImage crateQRCode(String content, Integer width, Integer height, String logoUrl, Integer logoWidth, Integer logoHeight) {
		if (StrUtil.isNotBlank(content)) {
			ServletOutputStream stream = null;

			HashMap<EncodeHintType, Comparable> hints = new HashMap<>(4);
			// 指定字符编码为utf-8
			hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
			// 指定二维码的纠错等级为中级
			hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
			// 设置图片的边距
			hints.put(EncodeHintType.MARGIN, 2);
			try {
				QRCodeWriter writer = new QRCodeWriter();
				BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
				BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
				for (int x = 0; x < width; x++) {
					for (int y = 0; y < height; y++) {
						bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
					}
				}
				if (StrUtil.isNotBlank(logoUrl)) {
					insertLogo(bufferedImage, width, height, logoUrl, logoWidth, logoHeight);
				}
				return bufferedImage;
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (stream != null) {
					try {
						stream.flush();
						stream.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
		return null;
	}
	/**
	 * 二维码插入logo
	 *
	 * @param source     二维码
	 * @param width      二维码宽度
	 * @param height     二维码高度
	 * @param logoUrl    logo 在线地址
	 * @param logoWidth  logo 宽度
	 * @param logoHeight logo 高度
	 * @throws Exception
	 */
	public static void insertLogo(BufferedImage source, Integer width, Integer height, String logoUrl, Integer logoWidth, Integer logoHeight) throws Exception {
		// logo 源可为 File/InputStream/URL
		Image src = ImageIO.read(new URL(logoUrl));
		// 插入LOGO
		Graphics2D graph = source.createGraphics();
		int x = (width - logoWidth) / 2;
		int y = (height - logoHeight) / 2;
		graph.drawImage(src, x, y, logoWidth, logoHeight, null);
		Shape shape = new RoundRectangle2D.Float(x, y, logoWidth, logoHeight, 6, 6);
		graph.setStroke(new BasicStroke(3f));
		graph.draw(shape);
		graph.dispose();
	}

	public static void main(String[] args) throws WriterException {
		File logoFile = new File("D://QrCode/logo3.png");
		File QrCodeFile = new File("D://QrCode/05.png");
		String url = "https://www.baidu.com/";
		String note = "访问百度连接";
		drawLogoQRCode(logoFile, QrCodeFile, url, note);
	}
}
